import unittest
from unittest.mock import patch, mock_open, MagicMock

from ascend_deployer.module_utils import common_info
from ascend_deployer.module_utils.common_info import get_npu_info


class TestCommonInfo(unittest.TestCase):

    def test_get_local_path(self):
        uid = 0
        user_dir = "/home/test"
        self.assertEqual(common_info.get_local_path(uid, user_dir), "/usr/local")
        uid = 1000
        self.assertEqual(common_info.get_local_path(uid, user_dir), user_dir + "/.local")

    def test_get_ascend_install_path(self):
        uid = 0
        user_dir = "/home/test"
        self.assertEqual(common_info.get_ascend_install_path(uid, user_dir), "/usr/local/Ascend")
        uid = 1000
        self.assertEqual(common_info.get_ascend_install_path(uid, user_dir), user_dir + "/Ascend")

    def test_get_os_version(self):
        # for centos
        os_id = "centos"
        os_version = "7"
        os_codename = "7 (Core)"
        content = 'CentOS Linux release 7.6.1810 (Core)'
        with patch("builtins.open", new_callable=mock_open, read_data=content) as mock_file:
            self.assertEqual("7.6", common_info.get_os_version(os_id, os_version, os_codename))

        # for euleros sp8
        os_id = "euleros"
        os_version = "2"
        os_codename = "2 (SP8)"
        self.assertEqual("2.8", common_info.get_os_version(os_id, os_version, os_codename))

        # for euleros sp11 - unsupported
        os_id = "euleros"
        os_version = "2"
        os_codename = "2 (SP11)"
        with self.assertRaises(RuntimeError) as context:
            common_info.get_os_version(os_id, os_version, os_codename)
        self.assertEqual("os euleros_2SP11 is not supported", str(context.exception))

        # for kylin, openeuler, mtos
        os_id = "openEuler"
        os_version = "22.03"
        os_codename = "22.03 LTS"
        self.assertEqual("22.03LTS", common_info.get_os_version(os_id, os_version, os_codename))

        # for ubuntu
        os_id = "ubuntu"
        os_version = "20.04"
        os_codename = "20.04 LTS (Focal Fossa)"
        self.assertEqual("20.04", common_info.get_os_version(os_id, os_version, os_codename))

        # for ubuntu - unsupported
        os_id = "ubuntu"
        os_version = "24.04"
        os_codename = "24.04 LTS (Lunar Lobster)"
        with self.assertRaises(RuntimeError) as context:
            common_info.get_os_version(os_id, os_version, os_codename)
        self.assertEqual("os ubuntu_24.04 is not supported", str(context.exception))

        # for uos - kernel1
        os_id = "uos"
        os_version = "20"
        os_codename = "20"
        with patch("platform.uname") as mock_uname:
            mock_uname.return_value = MagicMock(
                system="uos",
                node="uos-machine",
                release="4.19.90-2106.3.0.0095.up2.uel20",
                version="#1 SMP Debian 4.19.208-1 (2021-03-04)",
                machine="x86_64"
            )
            self.assertEqual("20-1020e", common_info.get_os_version(os_id, os_version, os_codename))
        # for uos - kernel2
        with patch("platform.uname") as mock_uname:
            mock_uname.return_value = MagicMock(
                system="uos",
                node="uos-machine",
                release="4.19.90-2211.5.0.0178.22.uel20",
                version="#1 SMP Debian 4.19.208-1 (2021-03-04)",
                machine="x86_64"
            )
            self.assertEqual("20-1050e", common_info.get_os_version(os_id, os_version, os_codename))
        # for uos - unsupported
        with patch("platform.uname") as mock_uname:
            mock_uname.return_value = MagicMock(
                system="uos",
                node="uos-machine",
                release="4.19.90-2004.5.0.0178.22.uel20",
                version="#1 SMP Debian 4.19.208-1 (2021-03-04)",
                machine="x86_64"
            )
            with self.assertRaises(RuntimeError) as context:
                common_info.get_os_version(os_id, os_version, os_codename)
            self.assertEqual("os uos_20 is not supported", str(context.exception))

        # for debian
        os_id = "debian"
        os_version = "10"
        os_codename = "10 (buster)"
        self.assertEqual("10", common_info.get_os_version(os_id, os_version, os_codename))

        # for debian - unsupported
        os_id = "debian"
        os_version = "11"
        os_codename = "10 (bullseye)"
        with self.assertRaises(RuntimeError) as context:
            common_info.get_os_version(os_id, os_version, os_codename)
        self.assertEqual("os debian_11bullseye is not supported", str(context.exception))

        # excluded os
        os_id = "linuxmint"
        os_version = "20.2"
        os_codename = "20.2 (Uma)"
        self.assertEqual(os_version, common_info.get_os_version(os_id, os_version, os_codename))

    def test_parse_os_release(self):

        # supported os
        content = '\nNAME="openEuler"\nVERSION="22.03 LTS"\nID="openEuler"\nVERSION_ID="22.03"\nPRETTY_NAME="openEuler 22.03 LTS"\nANSI_COLOR="0;31"'
        with patch("builtins.open", new_callable=mock_open, read_data=content) as mock_file:
            os_name, os_version = common_info.parse_os_release()
            self.assertEqual("OpenEuler", os_name)
            self.assertEqual("22.03LTS", os_version)

        # no supported os
        content = '\nNAME="Linux Mint"\nVERSION="20.2 (Uma)"\nID="linuxmint"\nVERSION_ID="20.2"\nPRETTY_NAME="Linux Mint 20.2 Uma"\nANSI_COLOR="0;31"'
        with patch("builtins.open", new_callable=mock_open, read_data=content) as mock_file:
            with self.assertRaises(RuntimeError) as context:
                common_info.parse_os_release()
            self.assertEqual("os linuxmint is not supported", str(context.exception))

    def test_get_scene_dict(self):
        resource_dir = "/home/test"
        common_info.get_scene_dict(resource_dir)

    def test_get_os_and_arch(self):
        machine = "x86_64"
        os_name, os_version = "EulerOS", "2.9"
        mock_func = "ascend_deployer.module_utils.common_info.parse_os_release"
        with patch("platform.machine", return_value=machine), \
            patch(mock_func, return_value=(os_name, os_version)):
            self.assertEqual("EulerOS_2.9_x86_64", common_info.get_os_and_arch())

        os_name, os_version = "EulerOS", "2.12"
        with patch("platform.machine", return_value=machine), \
            patch(mock_func, return_value=(os_name, os_version)):
            with self.assertRaises(RuntimeError) as context:
                common_info.get_os_and_arch()
            self.assertEqual("os EulerOS_2.12_x86_64 is not supported", str(context.exception))

    def test_need_skip_sys_package(self):
        os_and_arch = "EulerOS_2.12_x86_64"
        self.assertFalse(common_info.need_skip_sys_package(os_and_arch))
        os_and_arch = "UOS_20-1020e_aarch64"
        self.assertTrue(common_info.need_skip_sys_package(os_and_arch))

    def test_get_os_package_name(self):
        os_name, os_version = "EulerOS", "2.9"
        mock_func = "ascend_deployer.module_utils.common_info.parse_os_release"
        with patch(mock_func, return_value=(os_name, os_version)):
            with self.assertRaises(RuntimeError) as context:
                common_info.get_os_package_name()
            self.assertEqual("os EulerOS_2.9 is not supported", str(context.exception))
        os_name, os_version = "OpenEuler", "20.03LTS"
        with patch(mock_func, return_value=(os_name, os_version)):
            self.assertEqual("OpenEuler_20.03_LTS", common_info.get_os_package_name())

    def test_get_profile_model(self):
        model = "--"
        self.assertEqual("unknown", common_info.get_profile_model(model))

        model = "Atlas 900 (Model 9000)"
        self.assertEqual("A900-9000", common_info.get_profile_model(model))

        model = "A300T-9000"
        self.assertEqual("A800-9010", common_info.get_profile_model(model))

        model = "Atlas 800 (Model 3010)"
        self.assertEqual("A300-3010", common_info.get_profile_model(model))

    def test_get_npu_info(self):
        card = "Atlas 500 (Model 3000)"
        mock_func1 = "ascend_deployer.module_utils.common_info.parse_card"
        product_mode = "A300-3010"
        mock_func2 = "ascend_deployer.module_utils.common_info.parse_model"
        profile_model = "A300-3010"
        mock_func3 = "ascend_deployer.module_utils.common_info.get_profile_model"

        result = {"card": "Atlas 500 (Model 3000)", "model": "A300-3010", "scene": "infer", "product": "A300"}
        with patch(mock_func1, return_value=card), \
            patch(mock_func2, return_value=product_mode), \
            patch(mock_func3, return_value=profile_model):
            self.assertEqual(result, get_npu_info())




